#pragma once
// 实现语音识别子服务
/*
    1.包含语音识别客户端
    2.包含brpc服务器，其中实现SpeechServiceImpl为调用语音客户端对语音信息进行识别
    3.服务器注册客户端etcd
*/
#include <brpc/server.h>
#include <butil/logging.h>
#include "logger.hpp"  //日志模块封装
#include "asr.hpp"     //语音识别模块封装
#include "etcd.hpp"    //服务注册模块封装
#include "speech.pb.h" //protobuf框架代码

namespace zrb
{
    // （1）.创建rpc服务子类继承pb中的EchoService服务类，并实现内部的业务接口逻辑
    class SpeechServiceImpl : public zrb::SpeechService
    {
    public:
        SpeechServiceImpl(const ASRClient::ptr &asr_client)
            :_asr_client(asr_client)
        {
        }

        ~SpeechServiceImpl()
        {
        }

        void SpeechRecognition(google::protobuf::RpcController *controller,
                  const ::zrb::SpeechRecognitionReq *request,
                  ::zrb::SpeechRecognitionRsp *response,
                  ::google::protobuf::Closure *done)
        {
            brpc::ClosureGuard rpc_guard(done);
            // 1.取出请求中的语音数据
            std::string data = request->speech_content();
            // 2.调用语音sdk模块进行语音识别，得到响应
            string err;
            std::string result = _asr_client->recognize(request->speech_content(), err);
            if (result.empty())
            {
                LOG_ERROR("{}语音识别失败", request->request_id());
                response->set_request_id(request->request_id());
                response->set_success(false);
                response->set_errmsg("语音识别失败 " + err);
                return;
            }
            // 3.组织响应
            response->set_request_id(request->request_id());
            response->set_success(true);
            response->set_recognition_result(result);
        }
        private:
            ASRClient::ptr _asr_client;
    };

    // （2）.创建rpc服务器类，搭建服务器
    //  （3）.向服务器中添加rpc子服务对象 -- 告诉服务器收到什么请求用哪个接口处理
    class SpeechServer
    {
    public:
        using ptr = shared_ptr<SpeechServer>;
        SpeechServer(const ASRClient::ptr& asr_client,const Registry::ptr& rclient,const std::shared_ptr<brpc::Server>& rpc_server)
            : _asr_client(asr_client)
            ,_rclient(rclient) 
            ,_rpc_server(rpc_server)
        {
        }

        void start()
        {
            _rpc_server->RunUntilAskedToQuit();//休眠等待运行结束 
        }

        ~SpeechServer()
        {
        }

    private:
        ASRClient::ptr _asr_client;                      // 语音识别对象
        std::shared_ptr<brpc::Server> _rpc_server;       // brpc服务器对象
        Registry::ptr _rclient;                          // etcd服务器注册类
    };

    //SpeechServer构造过程参数太多，使用建造者模式
    class SpeechServerBuild
    {
    public:
        // 构造语音识别客户端对象
        void make_asr_object(const std::string &app_id,
                             const std::string &api_key,
                             const std::string &secret_key)
        {
            _asr_client = std::make_shared<ASRClient>(app_id,api_key,secret_key);
        }
        // 构造etcd服务注册对象
        // 网络Ip、注册的服务名称、注册的服务地址
        void make_reg_object(const std::string& host,const std::string& name,const std::string &access_host) 
        {
            _rclient = std::make_shared<Registry>(host);
            _rclient->registry(name,access_host); //服务注册
        }
        // 构造brpc服务对象
        // 端口 超时时间 线程数量
        void make_rpc_object(uint16_t port, uint32_t timeout, uint8_t thread_num)
        {
            //先启动语音模块，再启动rpc远程调用服务
            if(!_asr_client)
            {
                LOG_ERROR("还未初始化语音识别模块");
                abort();
            }
            _rpc_server = std::make_shared<brpc::Server>();

            //向服务器增加一个SpeechServiceImpl服务，SpeechServiceImpl服务是自己实现的
            SpeechServiceImpl* echo_service = new SpeechServiceImpl(_asr_client);
            //brpc::ServiceOwnership::SERVER_DOESNT_OWN_SERVICE 表示添加服务失败，服务器也不会删除服务对象
            //brpc::ServiceOwnership::SERVER_OWNS_SERVICE 表示添加服务失败时，服务器负责删除服务对象
            int ret = _rpc_server->AddService(echo_service, brpc::ServiceOwnership::SERVER_OWNS_SERVICE);
            if (ret == -1) {
                LOG_ERROR("添加Rpc服务失败！");
                abort();
            }

            //启动服务器
            brpc::ServerOptions options;
            options.idle_timeout_sec = timeout; //连接空闲超时时间-超时后连接被关闭
            options.num_threads = thread_num; // io线程数量
            ret = _rpc_server->Start(port, &options); //监听的端口
            if (ret == -1) {
                LOG_ERROR("rpc服务器启动失败");
                abort();
            }
        }
   
        SpeechServer::ptr build()
        {
            if(!_asr_client)
            {
                LOG_ERROR("还未初始化语音识别模块");
                abort();
            }
            if(!_rpc_server)
            {
                LOG_ERROR("还未初始化rpc服务模块");
                abort();
            }
            if(!_rclient)
            {
                LOG_ERROR("还未初始化服务注册客户端模块");
                abort();
            }
            SpeechServer::ptr server = std::make_shared<SpeechServer>(_asr_client,_rclient,_rpc_server);
            return server;
        }

    private:
        ASRClient::ptr _asr_client;                      // 语音识别对象
        std::shared_ptr<brpc::Server> _rpc_server;       // brpc服务器对象
        Registry::ptr _rclient;                          // etcd服务器注册类
    };
};
